package de.ghost23.common.process {
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;

	/**
	 * An ACommand is a concrete implementation of ICommand. It is normally used in conjunction
	 * with the Process or BranchProcess class. Within a command, a nearly isolated set of instructions can
	 * be put, that will be executed, when the command gets called. These instructions can
	 * either be synchronous or asynchronous. Therefore, the 'execute' method starts the
	 * ACommand, and when the command has finished, the ACommand should call its protected
	 * <code>setResult(resultCode:String)</code> method to signalize the end of this ACommand.
	 * 
	 * This class is to be seen as an abstract class and should not be used directly. It is
	 * recommended, that every ACommand for a simple Process extends this ACommand class.
	 * 
	 * An ACommand usually does not need an individual constructor, since the execute method
	 * is called immediately after constructing the ACommand.
	 * @author Sven Busse
	 * @version 1.0
	 */
	public class ACommand extends EventDispatcher implements ICommand {

		/**
		 * Default result code for expressing, that this command finished
		 * successfully. Use this in the <code>setResult(resultCode:String)</code> method.
		 * @see #setResult()
		 */
		public static const SUCCESS:String = "200";

		/**
		 * Default result code for expressing, that this command has failed.
		 * Use this in the <code>setResult(resultCode:String)</code> method.
		 * @see #setResult()
		 */
		public static const FAILURE:String = "500";
		
		/**
		 * Starts execution of this ACommand. This method has to be overridden
		 * by the subclass.
		 * @param	data Reference to the bundling data Dictionary.
		 */
		public function execute(data:Dictionary):void {
			
			setResult(SUCCESS);
		}
		
		/**
		 * Cancels this command. This command stops its execution and throws a ProcessEvent.FAILED event.
		 */
		public function cancel():void {
			
			setResult(FAILURE);
		}
		
		/**
		 * Implies, that this ACommand has finished. Call this method internally in your concrete
		 * ACommand, when it has finished. This way, asynchronous instructions are possible.
		 * @param resultCode If ACommand.SUCCESS, this command fires the ProcessEvent.COMPLETED Event, otherwise
		 * ProcessEvent.FAILED is fired.
		 */
		protected function setResult(resultCode:String):void {
			
			if (resultCode == SUCCESS) dispatchEvent(new ProcessEvent(ProcessEvent.COMPLETED));
			else if(resultCode == FAILURE) dispatchEvent(new ProcessEvent(ProcessEvent.FAILED));
			else dispatchEvent(new ProcessEvent(ProcessEvent.COMPLETED, resultCode, null));
		}

		/**
		 * Updates the progress of this command and dispatches it to the hosting process.
		 * Note: updating the progress with either 0 or 1 directly is not needed, because Process or
		 * BranchProcess respectively deal with the general start and finish of a command.
		 * @param progress A number between 0 and 1.
		 */
		protected final function updateProgress(progress:Number):void {

			dispatchEvent(new ProcessEvent(ProcessEvent.PROGRESS, null, null, progress));
		}
	}
}